#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>

using namespace std;

////////////////////////////////////////////////////////////////////////////////

LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::analyse() {
    programme();
    cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::programme() {
    // <programme> ::= debut <seqInst> fin FIN_FICHIER

    sauterSymCour("debut");
    seqInst();
    sauterSymCour("fin");
    testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::seqInst() {
    // <seqInst> ::= <inst> ; { <inst> ; }

    do {
	inst();
	sauterSymCour(";");
    } while ((ls.getSymCour() == "<VARIABLE>") | (ls.getSymCour() == "si") | (ls.getSymCour() == "tantque")
	    | (ls.getSymCour() == "repeter") | (ls.getSymCour() == "pour"));
    // tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::inst() {
    // <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter>

    if (ls.getSymCour() == "si") instSi();
    else if (ls.getSymCour() == "tantque") instTq();
    else if (ls.getSymCour() == "repeter") instRepeter();
    else if (ls.getSymCour() == "pour") instPour();
    else affectation();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instSi() {
    // <instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> } [ sinon <seqInst> ] finsi

    sauterSymCour("si");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    seqInst();

    while (ls.getSymCour() == "sinonsi") {
	ls.suivant();
	sauterSymCour("(");
	expBool();
	sauterSymCour(")");
	seqInst();
    }

    if (ls.getSymCour() == "sinon") seqInst();

    sauterSymCour("finsi");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instTq() {
    // <instTq> ::= tantque ( <expBool> ) <seqInst> fintantque

    sauterSymCour("tantque");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    seqInst();
    sauterSymCour("fintantque");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instRepeter() {
    // <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )

    sauterSymCour("repeter");
    seqInst();
    sauterSymCour("jusqua");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instPour() {
    // <instPour> :: = pour ( <affectation> ( <expBool> ) <affectation ) <seqInst> finpour  
    sauterSymCour("pour");
    sauterSymCour("(");
    affectation();
    sauterSymCour(";");

    expBool();

    sauterSymCour(";");
    affectation();
    sauterSymCour(")");
    seqInst();
    sauterSymCour("finpour");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::affectation() {
    // <affectation> ::= <variable> = <expression>

    testerSymCour("<VARIABLE>");
    ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour("=");
    expression();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::lire() {
    // <lire> ::= lire ( <variable> )
    sauterSymCour("lire");
    sauterSymCour("(");
    sauterSymCour("<VARIABLE>");
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::ecrire() {
    // <ecrire> ::= ecrire ( <expression> | <chaine> )
    sauterSymCour("ecrire");
    sauterSymCour("(");
    if (ls.getSymCour() == "<CHAINE>") ls.suivant();
    else expression();
    sauterSymCour(")");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expression() {
    // <expression> ::= <expressionArit> | (<expBool>) | <CHAINE>

    if (ls.getSymCour() == "(") {
	ls.suivant();
	expBool();
	sauterSymCour(")");
    } else if (ls.getSymCour() == "<CHAINE>") {
	ls.suivant();
    } else
	expArit();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expArit() {
    // <expressionArit> ::= <terme> { <opAdd> <terme> }

    terme();
    while (ls.getSymCour() == "+" || ls.getSymCour() == "-" || ls.getSymCour() == "*" || ls.getSymCour() == "/") {
	opAdd();
	terme();
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::facteur() {
    // <facteur> ::= <entier> | <variable> | <opUnaire> ( <expBool> ) | ( <expBool> )

    if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<ENTIER>") {
	ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
    } else if (ls.getSymCour() == "-" || ls.getSymCour() == "non") {
	opUnaire();
	sauterSymCour("(");
	expBool();
	sauterSymCour(")");
    } else if (ls.getSymCour() == "(") {
	ls.suivant();
	expBool();
	sauterSymCour(")");
    } else
	erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::terme() {
    // <terme> ::= <facteur> { <opMult> <facteur> }

    facteur();
    while (ls.getSymCour() == "*" || ls.getSymCour() == "/") {
	opMult();
	facteur();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opAdd() {
    // <opAdd> ::= + | -

    if (ls.getSymCour() == "+" || ls.getSymCour() == "-")
	ls.suivant();
    else
	erreur("<opAdd>");

}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opMult() {
    // <opMult> ::= * | /

    if (ls.getSymCour() == "*" || ls.getSymCour() == "/")
	ls.suivant();
    else
	erreur("<opMult>");

}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expBool() {
    // <expBool> ::= <relation> { <ou> <relation> }

    relation();
    while (ls.getSymCour() == "ou") {
	ls.suivant();
	relation();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::relation() {
    // <relation> ::= <condition> { <et> <condition> }

    condition();
    while (ls.getSymCour() == "et") {
	ls.suivant();
	relation();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::condition() {
    // <condition> ::= <expression> { <opRel> <expression> }

    expression();
    while (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<" ||
	    ls.getSymCour() == "<=" || ls.getSymCour() == ">" || ls.getSymCour() == ">=") {
	opRel();
	expression();
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opRel() {
    // <opRel> ::= == | != | < | <= | > | >=

    if (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<" ||
	    ls.getSymCour() == "<=" || ls.getSymCour() == ">" || ls.getSymCour() == ">=")
	ls.suivant();
    else
	erreur("<opRel>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opUnaire() {
    // <opUnaire> ::= - | non

    if (ls.getSymCour() == "-" || ls.getSymCour() == "non")
	ls.suivant();
    else
	erreur("<opUnaire>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::testerSymCour(string ch) {
    if (ls.getSymCour() != ch) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne()
		<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
		<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
		<< endl;
	exit(0); // plus tard, on levera une exception
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::sauterSymCour(string ch) {
    testerSymCour(ch);
    ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::erreur(string mess) {
    cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
	    << ls.getColonne() << endl << "   Attendu : " << mess << endl
	    << "   Trouve  : " << ls.getSymCour() << endl << endl;
    exit(0); // plus tard, on levera une exception
}
